/**
 * 事物代理
 * 
 * */
//@Proxy(bean=SqliteService,method=TX)
class SpringSqlite3TranscationProxy {

	//@Autowired
	springSqlite3Jdbc;

	log;

	//事物是否开启
	isTxOpen = false;

	/**
	 * 等待事物打开
	 * 如果是使用状态，则只能等待开启。同一时间只有一个事物被执行！
	 * */
	waitAllowOpen = (txId)=>{

		const log = this.log.method('waitAllowOpen');

		const _this = this;

		return new Promise( (r,n) => {

			if(!_this.isTxOpen){
				log.trace(`tx:${txId} => 开启事物`)
				_this.isTxOpen = true;
				return r('ok');
			}

			log.trace(`tx:${txId} => 等待事务开启`)

			const intervalIndex = setInterval(()=>{

				if(!_this.isTxOpen){
					log.trace(`tx:${txId} => 开启事物`)
					_this.isTxOpen = true;
					r('ok');
					clearInterval(intervalIndex);
				}

			},50)

		})
	}

	//方法代理
	//beanDefine:定义和注解  bean:实例
	doProxy(bean,beanDefine){

		const log = this.log.method("doProxy")

		const _this = this;

		const {springSqlite3Jdbc} = this;


		return {
			/**
				wrapBean {
					bean;//bean的名称
					methodFn;//原始函数对象
					methodName;//方法名称
					beanDefine;//bean的定义
					args;//原始参数
					next():object 调用原始参数
					invoke([args]):object 调用指定参数
					getMethodDefine():Method? 获取方法的元注解 可能为空
					getMethodAnnotation():Annotation? 获取注解信息 可能为空
				}
			*/
			method(wrapBean,method,args){

				//如果方法 最后一个参数 传入了 事物传播标识 则忽略事物代理
				if(args.length > 0 && args[args.length-1] === '$TX'){
					return wrapBean.invoke(args);
				}

				return new Promise( async (r,j) => {

					const txId = parseInt(Math.random()*10000); 

					//等待开启事物
					await _this.waitAllowOpen(txId);

					await springSqlite3Jdbc.run('BEGIN')

					try{

						const result = await wrapBean.invoke(args)

						log.trace(`tx:${txId} => 事物提交`);

						await springSqlite3Jdbc.run(`COMMIT`)

						r(result);

						_this.isTxOpen = false;

					}catch(e){

						log.trace(`tx:${txId} => 事物回滚`);

						await springSqlite3Jdbc.run(`ROLLBACK`)

						j(e);

						_this.isTxOpen = false;
					}

				})

			}
		}
	}
}

module.exports = {SpringSqlite3TranscationProxy}